﻿using Abp.Localization;
using Abp.MultiTenancy;
using AbpProjectTemplate.Domain.Users;
using AbpProjectTemplate.Extensions;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace AbpProjectTemplate.Components.Authorization
{
    public class PermissionDefine
    {
        public const string PermissionNamePrefix = "Permission";
        public const UserType DefaultUserType = UserType.Admin;
        public const MultiTenancySides DefaultTenancySides = MultiTenancySides.Host | MultiTenancySides.Tenant;

        public PermissionDefine(Type type)
        {
            if (!type.IsEnum)
                throw new AppUserFriendlyException($"{type}非枚举类型！");
            var defineAttribute = type.GetCustomAttribute<PermissionDefineAttribute>(false)
                        ?? new PermissionDefineAttribute(DefaultUserType);
            this.Name = CreateName(type);
            this.DisplayName = defineAttribute?.DisplayName;
            this.UserType = defineAttribute.UserType;
            this.MultiTenancySides = defineAttribute.MultiTenancySides;
        }

        public PermissionDefine(FieldInfo field)
        {
            var type = field.DeclaringType;
            if (!type.IsEnum)
                throw new AppUserFriendlyException($"{type}非枚举类型！");
            var parent = PermissionHelper.GetPermissionDefine(type);
            parent.ThrowUserFriendlyExceptionIfNull();

            var defineAttribute = field.GetCustomAttribute<PermissionDefineAttribute>(false);
            this.Name = CreateName(field);
            this.DisplayName = defineAttribute?.DisplayName;
            //usertype和MultiTenancySides如果未设置，从父级继承
            this.UserType = defineAttribute?.UserType ?? parent.UserType;
            this.MultiTenancySides = defineAttribute?.MultiTenancySides ?? parent.MultiTenancySides;
            this.Parent = parent;
            this.Type = type;
            this.Value = field.GetValue(null);
            parent.Children.Add(this);
        }

        private static string CreateName(string baseName)
        {
            return $"{PermissionNamePrefix}.{baseName}";
        }

        public static string CreateName(Type type)
        {
            return CreateName(type.Name);
        }

        public static string CreateName(FieldInfo field)
        {
            return CreateName($"{field.DeclaringType.Name}.{field.Name}");
        }
        /// <summary>
        /// 获取展示名称
        /// </summary>
        public ILocalizableString GetDisplayName()
        {
            return this.DisplayName.HasValue()
                 ? new FixedLocalizableString(this.DisplayName)
                 : new LocalizableString(this.Name, AppConsts.LocalizationSourceName);
        }
        /// <summary>
        /// 使用HasFlag检查给定的permission是否包含权限值
        /// </summary>
        public bool CheckValueFlag<TEnum>(TEnum permission)
            where TEnum : struct, Enum
        {
            var val = (TEnum)this.Value;
            return permission.HasFlag(val);
        }
        /// <summary>
        /// 获取权限的枚举值
        /// </summary>
        public TEnum GetValue<TEnum>()
            where TEnum : struct, Enum
        {
            return (TEnum)this.Value;
        }
        /// <summary>
        /// 权限枚举类型
        /// </summary>
        public Type Type { get; private set; }
        /// <summary>
        /// 枚举值
        /// </summary>
        public object Value { get; private set; }
        /// <summary>
        /// 权限名称({PermissionNamePrefix}.{UserType}.{Type.Name}.{FiledName})
        /// </summary>
        public string Name { get; private set; }
        /// <summary>
        /// 显示名称
        /// </summary>
        public string DisplayName { get; private set; }
        /// <summary>
        /// 权限的用户类型
        /// </summary>
        public UserType UserType { get; private set; }
        /// <summary>
        /// 权限的租户类型
        /// </summary>
        public MultiTenancySides MultiTenancySides { get; private set; }
        /// <summary>
        /// 父级权限
        /// </summary>
        public PermissionDefine Parent { get; private set; }
        /// <summary>
        /// 子权限
        /// </summary>
        public List<PermissionDefine> Children { get; set; } = new List<PermissionDefine>();
    }
}

